/*
 *    Copyright (c) 2018-2025, boss All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the boss developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: boss
 */
package com.hopes.bizz.close.basic.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.hopes.bizz.close.basic.dto.ClosedGeneralCarAuditDTO;
import com.hopes.bizz.close.basic.dto.ClosedGeneralCarDTO;
import com.hopes.bizz.close.basic.entity.ClosedGeneralCarEntity;
import com.hopes.bizz.close.basic.dto.ClosedGeneralCarExcelDTO;
import com.hopes.bizz.close.basic.entity.ClosedOperateAuditRecordEntity;
import com.hopes.bizz.close.basic.service.ClosedOperateAuditRecordService;
import com.hopes.bizz.close.basic.vo.ClosedGeneralCarExcelVO;
import com.hopes.bizz.close.basic.mapper.ClosedGeneralCarMapper;
import com.hopes.bizz.close.basic.service.ClosedGeneralCarService;
import com.hopes.bizz.close.basic.vo.ClosedGeneralCarVO;
import com.hopes.bizz.close.common.constant.BasicDicConstant;
import com.hopes.bizz.close.common.constant.CloseModuleEnums;
import com.hopes.bizz.close.common.constant.enums.ParkCloseSysDictEnum;
import com.hopes.bizz.common.core.validate.ValidatorUtils;
import com.hopes.boss.admin.api.resolver.DictResolver;
import com.hopes.boss.admin.api.resolver.enums.AdminDictEnum;
import com.hopes.boss.admin.api.resolver.enums.SysDictEnum;
import com.hopes.boss.common.core.constant.CommonConstants;
import com.hopes.boss.common.entity.ValidateImportBO;
import com.hopes.boss.common.excel.vo.ErrorMessage;
import com.hopes.boss.common.security.util.SecurityUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 园区普通车辆信息
 *
 * @author pig
 * @date 2023-10-23 17:28:41
 */
@Service
@RequiredArgsConstructor
public class ClosedGeneralCarServiceImpl extends ServiceImpl<ClosedGeneralCarMapper, ClosedGeneralCarEntity> implements ClosedGeneralCarService {

    private final ClosedOperateAuditRecordService closedOperateAuditRecordService;

    @Override
    public boolean save(ClosedGeneralCarEntity entity) {
        entity.setApplyUserId(SecurityUtils.getUserId());
        if (ObjUtil.isNull(entity.getApplyTime())) {
            entity.setApplyTime(Calendar.getInstance().getTime());
        }
        entity.setInParkFlag(CommonConstants.DEFAULT_FALSE_FLAG);
        entity.setAuditStatus(BasicDicConstant.CLOSE_GENERAL_CAR_AUDIT_STATUS_NOT_SUBMIT);
        return SqlHelper.retBool(getBaseMapper().insert(entity));
    }

    @Override
    public ClosedGeneralCarVO getVoById(Long id) {
        final ClosedGeneralCarEntity closedGeneralCarEntity = getBaseMapper().selectById(id);
        final LambdaQueryWrapper<ClosedOperateAuditRecordEntity> wrapper = Wrappers.<ClosedOperateAuditRecordEntity>lambdaQuery().eq(ClosedOperateAuditRecordEntity::getObjId, id);
        return new ClosedGeneralCarVO(closedGeneralCarEntity, closedOperateAuditRecordService.list(wrapper));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean submitById(Long id) {
        // 1、修改状态
        lambdaUpdate()
                .set(ClosedGeneralCarEntity::getAuditStatus, BasicDicConstant.CLOSE_GENERAL_CAR_AUDIT_STATUS_NOT_AUDIT)
                .eq(ClosedGeneralCarEntity::getId, id)
                .update();
        // 2、创建提交日志记录
        return closedOperateAuditRecordService.buildSaveOperateAuditRecord(id,
                CloseModuleEnums.GeneralCarOperateEnum.submit.getValue(),
                BasicDicConstant.CLOSE_GENERAL_CAR_AUDIT_STATUS_NOT_AUDIT, null, null);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveAndSubmit(ClosedGeneralCarEntity closedGeneralCar) {
        // 1、保存普通车辆申请
        closedGeneralCar.setApplyUserId(SecurityUtils.getUserId());
        if (ObjUtil.isNull(closedGeneralCar.getApplyTime())) {
            closedGeneralCar.setApplyTime(Calendar.getInstance().getTime());
        }
        closedGeneralCar.setInParkFlag(CommonConstants.DEFAULT_FALSE_FLAG);
        closedGeneralCar.setAuditStatus(BasicDicConstant.CLOSE_PERSON_AUDIT_STATUS_NOT_AUDIT);
        // 重写了save方法， 不可使用saveOrUpdate
        if (ObjUtil.isNull(closedGeneralCar.getId())) {
            getBaseMapper().insert(closedGeneralCar);
        } else {
            getBaseMapper().updateById(closedGeneralCar);
        }
        // 2、创建 && 提交日志
        return closedOperateAuditRecordService.buildSaveOperateAuditRecord(closedGeneralCar.getId(),
                CloseModuleEnums.GeneralCarOperateEnum.audit.getValue(),
                BasicDicConstant.CLOSE_VISITOR_AUDIT_STATUS_NOT_AUDIT, null, null);
    }

    /**
     * 构建日志记录数据
     * @return                         日志记录对象
     */
    private ClosedOperateAuditRecordEntity buildOperateAuditRecord( Long objId, String handleOperate, Integer handleOperateRes, String handleOperateDesc, String remark) {
        final ClosedOperateAuditRecordEntity entity = new ClosedOperateAuditRecordEntity();
        entity.setObjId(objId);
        entity.setHandleTime(Calendar.getInstance().getTime());
        entity.setHandleUserId(SecurityUtils.getUserId());
        entity.setHandleUserName(SecurityUtils.getUser().getName());
        entity.setHandleOperate(handleOperate);
        entity.setHandleOperateRes(DictResolver.getItemLabelByValue(ParkCloseSysDictEnum.close_general_car_audit_status, handleOperateRes));
        entity.setHandleOperateDesc(handleOperateDesc);
        entity.setHandleOperateRemark(remark);
        return entity;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean auditById(ClosedGeneralCarAuditDTO closedGeneralCarAuditDTO) {
        // 1、 修改对象
        lambdaUpdate()
                .set(ClosedGeneralCarEntity::getRemark, closedGeneralCarAuditDTO.getRemark())
                .set(ClosedGeneralCarEntity::getAuditStatus, closedGeneralCarAuditDTO.getAuditStatus())
                .set(ClosedGeneralCarEntity::getAuditTime, Calendar.getInstance().getTime())
                .set(ClosedGeneralCarEntity::getAuditResultDesc, closedGeneralCarAuditDTO.getAuditResultDesc())
                .eq(ClosedGeneralCarEntity::getId, closedGeneralCarAuditDTO.getId()).update();
        // 2、创建 && 提交日志
        return closedOperateAuditRecordService.save(
                buildOperateAuditRecord(closedGeneralCarAuditDTO.getId(),
                        CloseModuleEnums.GeneralCarOperateEnum.audit.getValue(),
                        closedGeneralCarAuditDTO.getAuditStatus(), closedGeneralCarAuditDTO.getAuditResultDesc(), closedGeneralCarAuditDTO.getRemark())
        );
    }

    @Override
    public IPage<ClosedGeneralCarEntity> getAppGeneralCarSelfPage(Page page, ClosedGeneralCarDTO closedGeneralCarDTO) {
        final LambdaQueryWrapper<ClosedGeneralCarEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ClosedGeneralCarEntity::getApplyUserId, SecurityUtils.getUserId());
        wrapper.eq(StrUtil.isNotBlank(closedGeneralCarDTO.getType()), ClosedGeneralCarEntity::getType, closedGeneralCarDTO.getType());
        wrapper.eq(StrUtil.isNotBlank(closedGeneralCarDTO.getType()) && closedGeneralCarDTO.getType().equals(CloseModuleEnums.ParkCompanyTypeEnum.company.name())
                && ObjUtil.isNotNull(closedGeneralCarDTO.getOrgId()), ClosedGeneralCarEntity::getOrgId, closedGeneralCarDTO.getOrgId());
        wrapper.eq(ObjUtil.isNotNull(closedGeneralCarDTO.getCarType()), ClosedGeneralCarEntity::getCarType, closedGeneralCarDTO.getCarType());
        wrapper.eq(ObjUtil.isNotNull(closedGeneralCarDTO.getPassType()), ClosedGeneralCarEntity::getPassType, closedGeneralCarDTO.getPassType());
        wrapper.eq(StrUtil.isNotBlank(closedGeneralCarDTO.getUseFlag()), ClosedGeneralCarEntity::getUseFlag, closedGeneralCarDTO.getUseFlag());
        wrapper.eq(ObjUtil.isNotNull(closedGeneralCarDTO.getAuditStatus()), ClosedGeneralCarEntity::getAuditStatus, closedGeneralCarDTO.getAuditStatus());
        wrapper.like(StrUtil.isNotBlank(closedGeneralCarDTO.getKeyword()), ClosedGeneralCarEntity::getLicencePlateNumber, closedGeneralCarDTO.getKeyword())
                .or().like(StrUtil.isNotBlank(closedGeneralCarDTO.getKeyword()), ClosedGeneralCarEntity::getPhone, closedGeneralCarDTO.getKeyword())
                .or().like(StrUtil.isNotBlank(closedGeneralCarDTO.getKeyword()), ClosedGeneralCarEntity::getCarOwner, closedGeneralCarDTO.getKeyword());
        wrapper.orderByDesc(ClosedGeneralCarEntity::getApplyTime);
        return this.page(page, wrapper);
    }


    @Override
    public ValidateImportBO<ClosedGeneralCarExcelDTO> validateImport(List<ClosedGeneralCarExcelDTO> excelDTOList) {
        ValidateImportBO<ClosedGeneralCarExcelDTO> bo = new ValidateImportBO<>();
        List<ErrorMessage> errorMessageList = new ArrayList<>();
        List<ClosedGeneralCarExcelDTO> saveList = new ArrayList<>();
        int successNum = 0;
        int failedNum = 0;

        for (ClosedGeneralCarExcelDTO closedGeneralCarExcelDTO : excelDTOList) {
            final String validateRes = ValidatorUtils.importValidateEntity(closedGeneralCarExcelDTO);
            if (StrUtil.isEmpty(validateRes)) {
                successNum++;
                saveList.add(closedGeneralCarExcelDTO);
            } else {
                failedNum++;
                errorMessageList.add(new ErrorMessage(closedGeneralCarExcelDTO.getLineNum(), new HashSet<>(){
                    private static final long serialVersionUID = 2114050778826325599L;
                    {
                        add(validateRes);
                    }
                }));
            }
        }

        bo.setErrorMessages(errorMessageList);
        bo.setSaveList(saveList);
        bo.setSuccessNum(successNum);
        bo.setFailedNum(failedNum);
        return bo;
    }

    @Override
    public ClosedGeneralCarEntity importDtoToEntity(ClosedGeneralCarExcelDTO excelDto) {
        ClosedGeneralCarEntity entity= new ClosedGeneralCarEntity();
        BeanUtils.copyProperties(excelDto, entity);
        if (StrUtil.isNotEmpty(excelDto.getUseFlagStr())) {
            entity.setUseFlag(DictResolver.getItemValueByLabel(SysDictEnum.yes_no_type, excelDto.getUseFlagStr()));
        }
        if(StrUtil.isNotEmpty(excelDto.getOrgIdStr())) {
            entity.setOrgId(DictResolver.getItemValueByLabel(AdminDictEnum.sys_company, excelDto.getOrgIdStr(), Long::valueOf));
        }
        if (StrUtil.isNotEmpty(excelDto.getCarTypeStr())) {
            entity.setCarType(DictResolver.getItemValueByLabel(ParkCloseSysDictEnum.close_general_car_type, excelDto.getCarTypeStr(), Integer::valueOf));
        }
        if (StrUtil.isNotEmpty(excelDto.getCarBelongStr())) {
            entity.setCarBelong(DictResolver.getItemValueByLabel(ParkCloseSysDictEnum.close_general_car_belong, excelDto.getCarBelongStr(), Integer::valueOf));
        }
        if (StrUtil.isNotEmpty(excelDto.getPassTypeStr())) {
            entity.setPassType(DictResolver.getItemValueByLabel(ParkCloseSysDictEnum.close_general_car_pass_type, excelDto.getPassTypeStr(), Integer::valueOf));
        }
        entity.setInParkFlag(CommonConstants.DEFAULT_FALSE_FLAG);
        entity.setAuditStatus(BasicDicConstant.CLOSE_GENERAL_CAR_AUDIT_STATUS_NOT_SUBMIT);
        return entity;
    }

    @Override
    public ClosedGeneralCarExcelVO exportEntityToVo(ClosedGeneralCarEntity entity) {
        ClosedGeneralCarExcelVO excelVO = new ClosedGeneralCarExcelVO();
        BeanUtils.copyProperties(entity, excelVO);
        excelVO.setVehicleLicenseStr(StrUtil.isNotEmpty(entity.getVehicleLicense()) ? "已上传" : "未上传");
        excelVO.setOrgIdStr(DictResolver.getItemLabelByValue(AdminDictEnum.sys_company, entity.getOrgId()));
        excelVO.setUseFlagStr(DictResolver.getItemLabelByValue(SysDictEnum.yes_no_type, entity.getUseFlag()));
        excelVO.setInParkFlagStr(DictResolver.getItemLabelByValue(SysDictEnum.yes_no_type, entity.getInParkFlag()));
        excelVO.setCarTypeStr(DictResolver.getItemLabelByValue(ParkCloseSysDictEnum.close_general_car_type, entity.getCarType()));
        excelVO.setCarBelongStr(DictResolver.getItemLabelByValue(ParkCloseSysDictEnum.close_general_car_belong, entity.getCarBelong()));
        excelVO.setPassTypeStr(DictResolver.getItemLabelByValue(ParkCloseSysDictEnum.close_general_car_pass_type, entity.getPassType()));
        excelVO.setAuditStatusStr(DictResolver.getItemLabelByValue(ParkCloseSysDictEnum.close_general_car_audit_status, entity.getAuditStatus()));
        return excelVO;
    }

    private ClosedGeneralCarExcelVO exportEntityToVo(ClosedGeneralCarEntity entity, Class<? extends ClosedGeneralCarExcelVO> clazz) {
        try {
            final ClosedGeneralCarExcelVO excelVO = clazz.getDeclaredConstructor().newInstance();
            BeanUtils.copyProperties(entity, excelVO);
            excelVO.setVehicleLicenseStr(StrUtil.isNotEmpty(entity.getVehicleLicense()) ? "已上传" : "未上传");
            excelVO.setOrgIdStr(DictResolver.getItemLabelByValue(AdminDictEnum.sys_company, entity.getOrgId()));
            excelVO.setUseFlagStr(DictResolver.getItemLabelByValue(SysDictEnum.yes_no_type, entity.getUseFlag()));
            excelVO.setInParkFlagStr(DictResolver.getItemLabelByValue(SysDictEnum.yes_no_type, entity.getInParkFlag()));
            excelVO.setCarTypeStr(DictResolver.getItemLabelByValue(ParkCloseSysDictEnum.close_general_car_type, entity.getCarType()));
            excelVO.setCarBelongStr(DictResolver.getItemLabelByValue(ParkCloseSysDictEnum.close_general_car_belong, entity.getCarBelong()));
            excelVO.setPassTypeStr(DictResolver.getItemLabelByValue(ParkCloseSysDictEnum.close_general_car_pass_type, entity.getPassType()));
            excelVO.setAuditStatusStr(DictResolver.getItemLabelByValue(ParkCloseSysDictEnum.close_general_car_audit_status, entity.getAuditStatus()));
            return excelVO;
        }catch (Exception e) {
            return null;
        }
    }

    @Override
    public List<?> exportExcelWithClass(List<ClosedGeneralCarEntity> poList, Class<? extends ClosedGeneralCarExcelVO> clazz) {
        this.beforeExportExcel();
        final List<ClosedGeneralCarExcelVO> voList = poList.stream().map(entity -> this.exportEntityToVo(entity, clazz)).filter(ObjUtil::isNotNull).collect(Collectors.toList());
        this.afterExportExcel();
        return voList;
    }

    @Override
    public IPage<ClosedGeneralCarEntity> queryAppGeneralCarAuditPage(Page page, List<Integer> auditStatusList, ClosedGeneralCarDTO closedGeneralCarDTO) {
        final LambdaQueryWrapper<ClosedGeneralCarEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.in(CollUtil.isNotEmpty(auditStatusList), ClosedGeneralCarEntity::getAuditStatus, auditStatusList);
        wrapper.eq(StrUtil.isNotBlank(closedGeneralCarDTO.getType()), ClosedGeneralCarEntity::getType, closedGeneralCarDTO.getType());
        wrapper.eq(StrUtil.isNotBlank(closedGeneralCarDTO.getType()) && closedGeneralCarDTO.getType().equals(CloseModuleEnums.ParkCompanyTypeEnum.company.name())
                && ObjUtil.isNotNull(closedGeneralCarDTO.getOrgId()), ClosedGeneralCarEntity::getOrgId, closedGeneralCarDTO.getOrgId());
        wrapper.eq(ObjUtil.isNotNull(closedGeneralCarDTO.getCarType()), ClosedGeneralCarEntity::getCarType, closedGeneralCarDTO.getCarType());
        wrapper.eq(ObjUtil.isNotNull(closedGeneralCarDTO.getPassType()), ClosedGeneralCarEntity::getPassType, closedGeneralCarDTO.getPassType());
        wrapper.eq(StrUtil.isNotBlank(closedGeneralCarDTO.getUseFlag()), ClosedGeneralCarEntity::getUseFlag, closedGeneralCarDTO.getUseFlag());
        wrapper.eq(ObjUtil.isNotNull(closedGeneralCarDTO.getAuditStatus()), ClosedGeneralCarEntity::getAuditStatus, closedGeneralCarDTO.getAuditStatus());
        wrapper.like(StrUtil.isNotBlank(closedGeneralCarDTO.getKeyword()), ClosedGeneralCarEntity::getLicencePlateNumber, closedGeneralCarDTO.getKeyword())
                .or().like(StrUtil.isNotBlank(closedGeneralCarDTO.getKeyword()), ClosedGeneralCarEntity::getPhone, closedGeneralCarDTO.getKeyword())
                .or().like(StrUtil.isNotBlank(closedGeneralCarDTO.getKeyword()), ClosedGeneralCarEntity::getCarOwner, closedGeneralCarDTO.getKeyword());
        wrapper.orderByDesc(ClosedGeneralCarEntity::getApplyTime);
        return this.page(page, wrapper);
    }


}
